/*
 * GWTTask.java - Created on Jul 18, 2006
 * 
 * Copyright (C) 2006 Contix Technologies
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
package dk.contix.ant.gwt;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;


/**
 * Ant task for compiling Google Web Toolkit modules.
 * 
 * <p>The task can be used to compile any number of modules. It's not necessary to specify the module names directly. Instead, the
 * task accepts filesets specifying the modules.</p>
 * 
 * Place the ant-gwt.jar file in your project's lib dir, make sure that the gwt-*.jar files are there too, and use like this:
 * <pre>
 * &lt;path id="classpath"&gt;
 *   &lt;pathelement location="${srcdir}"/&gt;
 *   &lt;pathelement location="${builddir}"/&gt;
 *   &lt;fileset dir="lib"&gt;
 *     &lt;include name="*.jar"/&gt;
 *   &lt;/fileset&gt;
 * &lt;/path&gt;
 * 
 * &lt;target name="compile"&gt;
 *   &lt;javac ... /&gt;
 *   
 *   &lt;taskdef resource="dk/contix/ant/gwt/ant-gwt.xml" classpathref="classpath" /&gt;
 *   &lt;gwtcompile destdir="www" optimize="true"&gt;
 *     &lt;fileset dir="src"&gt;
 *       &lt;include name="**&#47;*.gwt.xml"/&gt;
 *     &lt;/fileset&gt;
 *   &lt/gwtcompile&gt;
 * &lt;target/&gt;
 * </pre>
 * 
 * <p>Please note that the order of the classpath is important. If you get weird errors about files not being found, then ensure that
 * the source directory is first, then the locally compiled classes, and then the jar files.</p>
 * 
 * <p>It's possible to enable some simple optimization by setting optimize="true" on gwtcompile. That will try to analyze the java files to see
 * if any of the required files have been changed since last compile. Required files are all files which are included in the source tag in the .gwt.xml-files.</p>
 * 
 * @author Joakim Recht &lt;recht@contix.dk&gt; - <a href="http://braindump.dk/tech/2006/07/18/ant-task-for-google-web-toolkit/">http://braindump.dk/tech/2006/07/18/ant-task-for-google-web-toolkit/</a>
 */
public class GWTCompileTask extends Task {

	private ClassLoader oldClassLoader;
	private String oldClasspath;
	private final CompileConfig config;
	private String version = "1.5";

	public GWTCompileTask() {
		try {
			oldClassLoader = Thread.currentThread().getContextClassLoader();
			oldClasspath = ((AntClassLoader)getClass().getClassLoader()).getClasspath();
			String[] cp = ((AntClassLoader)getClass().getClassLoader()).getClasspath().split(File.pathSeparator);
			URL[] urls = new URL[cp.length];
			for (int i = 0; i < cp.length; i++) {
				urls[i] = new File(cp[i]).toURI().toURL();
			}

			Thread.currentThread().setContextClassLoader(new URLClassLoader(urls, oldClassLoader) {
				public String toString() {
					return "custom";
				}
			});
			((AntClassLoader)getClass().getClassLoader()).setParent(Thread.currentThread().getContextClassLoader());
			((AntClassLoader)getClass().getClassLoader()).setClassPath(new Path(getProject()));
		} catch (MalformedURLException e) {
			throw new RuntimeException("Unable to initialize classloaders");
		}

		config = new CompileConfig();
	}

	/**
	 * Set the destination directory.
	 * 
	 * The directory must exist before the task is executed.
	 * 
	 * @param destdir Dir where generated files are placed.
	 */
	public void setDestdir(String destdir) {
		config.setDestdir(destdir);
	}

	/**
	 * Set the compile style.
	 * @param style Style. Available values are: "obfuscated", "pretty", "detailed". Default is obfuscated.
	 */
	public void setStyle(String style) {
		config.setStyle(style);
	}

	/**
	 * Set the log level for the compiler.
	 * @param level "all", "trace", "spam", "debug", "info", "warn", "error". Default is info.
	 */
	public void setLoglevel(String level) {
		config.setLoglevel(level);
	}

	public void execute() {

		config.validate();
		try {
			if ("1.5".equals(version) || "1.4".equals(version)) {
				new GWT15Compile(config, getProject()).execute();
			} else if ("1.6".equals(version)) {
				new GWT16Compile(config, getProject()).execute();
			} else {
				throw new BuildException("Version " + version + " not supported, only 1.4, 1.5 and 1.6 is allowed");
			}
		} finally {
			Thread.currentThread().setContextClassLoader(oldClassLoader);
			((AntClassLoader)getClass().getClassLoader()).setParent(Thread.currentThread().getContextClassLoader());
			((AntClassLoader)getClass().getClassLoader()).setClassPath(new Path(getProject(), oldClasspath));
		}
	}

	/**
	 * Add a fileset containing the modules to compile.
	 * 
	 * This should be a set of files matching *.gwt.xml.
	 * @param fileset
	 */
	public void addFileset(FileSet fileset) {
		config.addFileset(fileset);
	}

	/**
	 * Enable or disable optimization.
	 * 
	 * When this is set to <code>true</code>, the compiler is only run if any of the included java files have been changed since last compilation.
	 * 
	 * @param optimize <code>true</code> to enable, <code>false</code> to disable. By default, optimization is disabled.
	 */
	public void setOptimize(String optimize) {
		config.setOptimize(optimize);
	}
	
	public void setVersion(String version) {
		this.version = version;
	}
	
	public void setGendir(String genDir) {
		config.setGenDir(genDir);
	}

	public void setWorkdir(String workDir) {
		config.setWorkDir(workDir);
	}
}
